package com.game.utils.log;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;


/**
 * Log：日志封装工具类
 * <br>说明：
 * <br>1、作用：通过该类统一输出日志，方便运行阶段屏蔽部分日志。
 * <br>2、测试代码：建议使用该类输出日志。
 * <br>3、打印异常：建议使用该类printStackTrace方法输出异常。
 * <br>4、日志文件：非重要日志，可以使用本类对应方法输出日志；重要日志，需要每个类自己创建logger实例，并打印日志。
 * @author Liyuan
 */

public class Log {
	/** log */
	private static final Logger log = Logger.getLogger(Log.class);
	/** debug: true-调试环境, false-正式运行环境 */
	private static boolean debug = false;
	
	static {
		if (debug) log.setLevel(Level.DEBUG);
	}
	
	/** 日志级别枚举 */
	public static enum ELOG_LEVEL{
		DEBUG, INFO, WARN, ERROR
	}
	
	/**
	 * 创建日志输出对象，并设置DEBUG级别
	 * @param c
	 * @return
	 */
	public static Logger getLogger(Class c) {
		Logger log = Logger.getLogger(c);
		if (debug) log.setLevel(Level.DEBUG);
		return log;
	}
	
	//print
	/** println */
	private static void println(){
		if(debug) System.out.println();
	}
	
	/** println */
	private static void println(Object message){
		if(debug) System.out.println(message);
	}
	
	/** println */
	private static void println(Object message, boolean err){
		if(err){
			if(debug) System.err.println(message);
		} else {
			if(debug) System.out.println(message);
		}
	}
	
	/** print */
	private static void print(Object message){
		if(debug) System.out.print(message);
	}
	
	/** print */
	private static void print(Object message, boolean err){
		if(err){
			if(debug) System.err.print(message);
		} else {
			if(debug) System.out.print(message);
		}
	}
	
	//log
	/** debug */
	public static void debug(Object message){
		log.debug(message);
	}
	
	/**
	 * Debug日志输出方法
	 * @param otherLog 日志输出类，由其他业务类创建，便于代码跟踪
	 * @param message 消息
	 */
	public static void debug(Logger otherLog, Object message) {
		if (otherLog == null) 
			otherLog = log;
		else 
			if (debug) otherLog.setLevel(Level.DEBUG);
		otherLog.debug(message);
	}
	
	/** info */
	public static void info(Object message){
		log.info(message);
	}
	
	/**
	 * Info日志输出方法
	 * @param otherLog 日志输出类，由其他业务类创建，便于代码跟踪
	 * @param message 消息
	 */
	public static void info(Logger otherLog, Object message) {
		if (otherLog == null) 
			otherLog = log;
		otherLog.debug(message);
	}
	
	/** warn */
	public static void warn(Object message){
		println(message, true);
		log.warn(message);
	}
	
	/**
	 * Warn日志输出方法
	 * @param otherLog 日志输出类，由其他业务类创建，便于代码跟踪
	 * @param message 消息
	 */
	public static void warn(Logger otherLog, Object message) {
		if (otherLog == null) 
			otherLog = log;
		otherLog.debug(message);
	}
	
	/** error */
	public static void error(Object message){
		println(message, true);
		log.error(message);
	}
	
	/**
	 * Error日志输出方法
	 * @param otherLog 日志输出类，由其他业务类创建，便于代码跟踪
	 * @param message 消息
	 */
	public static void error(Logger otherLog, Object message) {
		if (otherLog == null) 
			otherLog = log;
		otherLog.debug(message);
	}
	
	/** log */
	public static void log(Object message){
		log.info(message);
	}
	
	/** log */
	public static void log(Object message, ELOG_LEVEL logLevel){
		switch(logLevel){
			case DEBUG: debug(message); break;
			case INFO: 	info(message);  break;
			case WARN: 	warn(message);  break;
			case ERROR: error(message); break;
			default: 	debug(message); break;
		}
	}
	
	public static void printStackTrace(Throwable cause){
		println(cause.getMessage(), true);
		if(debug) {
			cause.printStackTrace();
		} else {
			printStackTrace(50, cause);
			cause.printStackTrace();
		}
	}
	
	public static void printStackTrace(int limit, Throwable cause){
//		if(! debug) return;
		StackTraceElement[] elements = cause.getStackTrace();
		if(limit < 0) limit = 0;
		log.error("--------------------START----------------------------");
		log.error("捕获到异常:" + cause);
		for (int i = 0; i < elements.length; i++) {
			if(i >= limit ) break;
			log.error("at "+elements[i]);
		}
		log.error("---------------------END----------------------------");
	}
	
	/** traceMemory */
	public static void traceMemory(){
		Runtime runtime = Runtime.getRuntime();
		long totalMemory = runtime.totalMemory(); //内存总量
		long maxMemory = runtime.maxMemory(); //试图使用的最大内存
		long freeMemory = runtime.freeMemory(); //空闲内存
		String memoryInfo = "试图使用的最大内存:" + formatFileSize(maxMemory) + 
				"B, 内存总量:" + formatFileSize(totalMemory) + 
				"B, 空闲内存:" + formatFileSize(freeMemory) + "B";
		error(memoryInfo);
	}
	
	public static String formatFileSize(long fileS) {// 转换文件大小
		DecimalFormat df = new DecimalFormat("#.00");
		String fileSizeString = "";
		if (fileS < 1024) {
			fileSizeString = df.format((double) fileS) + "B";
		} else if (fileS < 1048576) {
			fileSizeString = df.format((double) fileS / 1024) + "K";
		} else if (fileS < 1073741824) {
			fileSizeString = df.format((double) fileS / 1048576) + "M";
		} else {
			fileSizeString = df.format((double) fileS / 1073741824) + "G";
		}
		return fileSizeString;
	}
	
	//cout Object
	public static void cout(Object obj){
		println(obj);
	}
	
	public static void cout(Object... args){
		if(args == null || args.length == 0) return;
		for (Object obj : args) {
			print(obj + "\t");
		}
		println();
	}
	
	public static void cout(Object[] args, String sign){
		if(args == null || args.length == 0) return;
		for(Object s : args){
			print(s + sign);
		}
		println();
	}
	
	public static void cout(String sign, Object... args){
		if(args == null || args.length == 0) return;
		for(Object s : args){
			print(s + sign);
		}
		println();
	}
	
	//cout String
	public static void cout(String s){
		println(s);
	}
	
	public static void cout(String... args){
		if(args == null || args.length == 0) return;
		for (Object obj : args) {
			print(obj + "\t");
		}
		println();
	}
	
	public static void cout(String[] args, String sign){
		if(args == null || args.length == 0) return;
		for(String s : args){
			print(s + sign);
		}
		println();
	}
	
	public static void cout(String sign, String... args){
		if(args == null || args.length == 0) return;
		for(String s : args){
			print(s + sign);
		}
		println();
	}
	
	//cout Collection
	public static void cout(Collection<Object> coll){
		if(coll == null) return;
		for(Object object : coll){
			print(object + "\t");
		}
		println();
	}
	
	public static void cout(Collection<Object> coll, String sign){
		if(coll == null) return;
		for(Object object : coll){
			print(object + sign);
		}
		println();
	}
	
	//cerr Object
	public static void cerr(Object obj){
		println(obj, true);
	}
	
	public static void cerr(Object... args){
		if(args == null || args.length == 0) return;
		for (Object obj : args) {
			print(obj + "\t", true);
		}
		println();
	}
	
	public static void cerr(Object[] args, String sign){
		if(args == null || args.length == 0) return;
		for(Object s : args){
			print(s + sign, true);
		}
		println();
	}
	
	public static void cerr(String sign, Object... args){
		if(args == null || args.length == 0) return;
		for(Object s : args){
			print(s + sign, true);
		}
		println();
	}
	
	//cerr String
	public static void cerr(String s){
		println(s, true);
	}
	
	public static void cerr(String... args){
		if(args == null || args.length == 0) return;
		for (Object obj : args) {
			print(obj + "\t", true);
		}
		println();
	}
	
	public static void cerr(String[] args, String sign){
		if(args == null || args.length == 0) return;
		for(String s : args){
			print(s + sign, true);
		}
		println();
	}
	
	public static void cerr(String sign, String... args){
		if(args == null || args.length == 0) return;
		for(String s : args){
			print(s + sign, true);
		}
		println();
	}
	
	//cerr Collection
	public static void cerr(Collection<Object> coll){
		if(coll == null) return;
		for(Object object : coll){
			print(object + "\t", true);
		}
		println();
	}
	
	public static void cerr(Collection<Object> coll, String sign){
		if(coll == null) return;
		for(Object object : coll){
			print(object + sign, true);
		}
		println();
	}
	
	/** testLog */
	private static void testLog(){
		Object message = new String("测试日志");
		Log.debug(message);
		Log.info(message);
		Log.warn(message);
		Log.error(message);
		Log.log(message, ELOG_LEVEL.INFO);
		println();
	}
	
	/** testPrint */
	private static void testPrint(){
		Object message = new String("测试日志");
		Log.cout(message);
		Log.cout(message, message, message);
		Log.cout(new String[]{"liyuan", "king"});
		Log.cerr(message);
		Log.cerr(message, message, message);
		Log.cerr(new String[]{"liyuan", "king"});
		println();
		
		List<Object> list = new ArrayList<Object>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add("liyuan");
		Log.cout(list);
		Log.cout(list, "\n");
		Log.cerr(list);
		Log.cerr(list, "\n");
		println();
		
		Map<Object, Object> map = new HashMap<Object, Object>();
		map.put(1, "liyuan");
		map.put("key", "value");
		Log.cout(map.keySet());
		Log.cout(map.values());
		Log.cerr(map.keySet());
		Log.cerr(map.values());
	}
	
	/** testMemory */
	private static void testMemory(){
		Runtime runtime = Runtime.getRuntime();
		println("最大内存" + runtime.maxMemory() + ", 已用内存" + runtime.totalMemory() + ", 可用内存" + runtime.freeMemory());
		
		String s = "";
		long start = System.currentTimeMillis();
		println("浪费内存中.....");
		for(int j = 0; j < 10000;j++) s += j;
		long end = System.currentTimeMillis();
		println("执行时间：" + ( end - start )+ "毫秒");
		
		println("最大内存" + runtime.maxMemory() + ", 已用内存" + runtime.totalMemory() + ", 可用内存" + runtime.freeMemory());
		runtime.gc();
		println("最大内存" + runtime.maxMemory() + ", 已用内存" + runtime.totalMemory() + ", 可用内存" + runtime.freeMemory());
	}
	
}
